#include "util.hpp"

class ServerTcp
{
public:
    ServerTcp(uint16_t port, std::string ip = "") : port_(port), ip_(ip), listensock_(-1)
    {
    }

    void init()
    {
        // 1.创建套接字
        listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock_ < 0)
        {
            logMessage(FATAL, "socket create fail————: %s\n", strerror(errno));
            exit(SOCKET_ERR);
        }
        logMessage(DEBUG, "socket create success: %s,listensock_:%d\n",
                   strerror(errno), listensock_);
        // 2.bin绑定
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family = PF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));
        if (bind(listensock_, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind fail————: %s\n", strerror(errno));
            exit(BIND_ERR);
        }
        logMessage(DEBUG, "bind success: %s\n", strerror(errno));
        // 3.设置监听状态
        if (listen(listensock_, 5) < 0)
        {
            logMessage(FATAL, "listen fail————: %s\n", strerror(errno));
            exit(LISTEN_ERR);
        }
        logMessage(DEBUG, "listen success: %s,listensock_:%d\n", strerror(errno),listensock_);
    }
    void loop()
    {
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // 4.服务器获取连接 accept
            int serverSock = accept(listensock_, (struct sockaddr *)&peer, &len);
            if (serverSock < 0)
            {
                logMessage(WARNNING, "accept fail————: %s[%d]\n", strerror(errno), serverSock);
                std::cout<<"listensock_:"<<listensock_<<std::endl;
                sleep(1);
                continue;
            }
            // 5.获取客户端基本信息。
            uint16_t peerPort = ntohs(peer.sin_port);
            std::string peerIp = inet_ntoa(peer.sin_addr);
            logMessage(DEBUG, "accept success: %s | %s[%d],socket fd: %d\n",
                       strerror(errno), peerIp.c_str(), peerPort, serverSock);
            // 6.提供服务 读取并处理任务
            tranService(serverSock, peerIp, peerPort);
        }
    }
    void tranService(int sock, const std::string &clientIp, uint16_t clientPort)
    {
        assert(sock >= 0);
        assert(!clientIp.empty());
        assert(clientPort >= 1024);

        char inbuffer[BUFFER_SIZE];
        while (true)
        {
            ssize_t s = read(sock, inbuffer, sizeof(inbuffer) - 1);
            if (s > 0)
            {
                inbuffer[s] = '\0'; // 漏写！！！！！
                if (strcasecmp(inbuffer, "quit") == 0)
                {
                    logMessage(DEBUG, "client quit -- %s[%d]", clientIp.c_str(), clientPort);
                    break;
                }
                for (int i = 0; i < s; i++)
                {
                    if (isalpha(inbuffer[i]) && islower(inbuffer[i]))
                    {
                        inbuffer[i] = toupper(inbuffer[i]);
                    }
                }
                logMessage(DEBUG, "trans after: %s[%d]>>> %s",
                           clientIp.c_str(), clientPort, inbuffer);
                write(sock, inbuffer, strlen(inbuffer));
            }
            else if (s == 0) // s == 0，代表对端关闭
            {
                logMessage(DEBUG, "client quit -- %s[%d]", clientIp.c_str(), clientPort);
                break;
            }
            else
            {
                logMessage(DEBUG, "%s[%d] - read: %s", clientIp.c_str(), clientPort, strerror(errno));
                break;
            }
        }
        // 只要走到这里，一定是client退出了，服务到此结束
        close(sock); // 如果一个进程对应的文件fd，打开了没有被归还，文件描述符泄漏！
        logMessage(DEBUG, "server close %d done", sock);
    }

private:
    int listensock_;
    uint16_t port_;
    std::string ip_;
};
void Usage(std::string proc)
{
    std::cerr << "Usage:\n\t" << proc << " port ip" << std::endl;
    std::cerr << "exmaple:\n\t" << proc << " 8080 127.0.0.11\n"
              << std::endl;
}
// ./serverTcp local_port local_ip
// ./serverTcp 8080
int main(int argc, const char *argv[])
{
    if (argc != 3 && argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    std::string ip;
    if (argc == 3)
    {
        ip=argv[2];
    }
    ServerTcp svr(port,ip);
    svr.init();
    svr.loop();
    return 0;
}